﻿/******************************************************************************************************
Copyright (c) 2014 Steven Giacomelli (stevegiacomelli@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************************************/

using System;

namespace SharpGeo
{
    /// <summary>
    /// Base class for all map layers
    /// </summary>
    public abstract class MapLayer
    {
        #region Constructor

        /// <summary>
        /// Constructs a MapLayer
        /// </summary>
        /// <param name="layerId">The layer's UniqueID</param>
        /// <param name="layerName">The layer's display name</param>
        protected MapLayer(Guid layerId, string layerName)
        {
            _layerId = layerId;
            _layerName = layerName;

            _envelope = Envelope.Empty;
            _coordinateReferenceSystem = SharpGeo.CoordinateReferenceSystem.LoadWgs84();

            _isLayerHidden = false;
            _blendingMode = SharpGeo.BlendingMode.Normal;

            _minimumScale = 0;
            _maximumScale = double.MaxValue;
        }

        #endregion Constructor

        #region Fields

        private Guid _layerId;
        private string _layerName;

        private Envelope _envelope;
        private CoordinateReferenceSystem _coordinateReferenceSystem;

        private BlendingMode _blendingMode;
        private bool _isLayerHidden;
        private double _minimumScale;
        private double _maximumScale;

        private GeometryAttributes _attributes = new GeometryAttributes();

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the Map this layer is associated with
        /// </summary>
        public Map Map { get; set; }

        /// <summary>
        /// Gets the unique ID
        /// </summary>
        public Guid LayerId { get { return _layerId; } protected set { _layerId = value; } }

        /// <summary>
        /// Gets or sets the display nam.
        /// </summary>
        public string LayerName
        {
            get { return !string.IsNullOrEmpty(_layerName) ? _layerName : "[Unnamed]"; }
            set
            {
                if (!string.IsNullOrWhiteSpace(value))
                {
                    _layerName = value.Trim();
                    OnChanged();
                }
            }
        }

        /// <summary>
        /// Gets the CoordinateReferenceSystem
        /// </summary>
        public CoordinateReferenceSystem CoordinateReferenceSystem { get { return _coordinateReferenceSystem; } }

        /// <summary>
        /// Gets this layer's envelope
        /// </summary>
        public virtual Envelope Envelope { get { return _envelope; } protected set { _envelope = value; } }

        /// <summary>
        /// Gets or sets the blending mode
        /// </summary>
        public BlendingMode BlendingMode
        {
            get
            {
                return _blendingMode;
            }
            set
            {
                _blendingMode = value;
                OnChanged();
            }
        }

        /// <summary>
        /// Indicates if the layer is hidden (user pref).
        /// </summary>
        public bool IsLayerHidden
        {
            get
            {
                return _isLayerHidden;
            }
            set
            {
                _isLayerHidden = value;
                OnChanged();
            }
        }

        /// <summary>
        /// Gets or sets the minimum scale at which this layer should be displayed
        /// </summary>
        public double MinimumScale
        {
            get
            {
                return _minimumScale;
            }
            set
            {
                _minimumScale = value;
                OnChanged();
            }
        }

        /// <summary>
        /// Gets or sets the maximum scale at which this layer should be displayed
        /// </summary>
        public double MaximumScale
        {
            get
            {
                return _maximumScale;
            }
            set
            {
                _maximumScale = value;
                OnChanged();
            }
        }

        /// <summary>
        /// Gets or sets the flag that supresses change notifications
        /// </summary>
        protected bool SuppressChangeNotifications { get; set; }

        /// <summary>
        /// Gets the custom attributes of this layer
        /// </summary>
        public GeometryAttributes Attributes
        {
            get { return _attributes.AsReadOnly; }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Notifies the map that this layer has changed
        /// </summary>
        protected virtual void OnChanged()
        {
            if (Map != null && !SuppressChangeNotifications)
            {
                Map.OnMapLayerChanged(this);
            }
        }

        /// <summary>
        /// Sets the custom attributes of this layer
        /// </summary>
        /// <param name="attributes">The attributes to attach to this layer</param>
        public void SetAttributes(GeometryAttributes attributes)
        {
            _attributes.SetAttributes(attributes);
        }

        /// <summary>
        /// Adds attributes to the current attributes of the layer
        /// </summary>
        /// <param name="attributes">The attributes to add</param>
        public void AddAttributes(GeometryAttributes attributes)
        {
            if (attributes == null || attributes.Count == 0)
                return;

            foreach (var attr in attributes)
            {
                _attributes.AddAttribute(attr.Key, attr.Value);
            }
        }

        /// <summary>
        /// Sets the CoordinateReferenceSystem for this layer
        /// </summary>
        /// <param name="coordinateReferenceSystem">The CoordinateReferenceSystem to set</param>
        public void SetCoordinateReferenceSystem(CoordinateReferenceSystem coordinateReferenceSystem)
        {
            SetCoordinateReferenceSystem(coordinateReferenceSystem, false);
        }

        /// <summary>
        /// Sets the CoordinateReferenceSystem for this layer
        /// </summary>
        /// <param name="coordinateReferenceSystem">The CoordinateReferenceSystem to set</param>
        /// <param name="transform">True to transform the layer to the new CoordinateReferenceSystem</param>
        public void SetCoordinateReferenceSystem(CoordinateReferenceSystem coordinateReferenceSystem, bool transform)
        {
            if (transform && coordinateReferenceSystem != null)
            {
                //transform the layer to the new crs
            }

            _coordinateReferenceSystem = coordinateReferenceSystem;
        }

        #endregion Methods
    }
}